package cn.touna.jss.modules.third.tx;

import cn.touna.risk.api.contraints.facet.Four;
import cn.touna.risk.api.contraints.facet.Second;
import cn.touna.risk.api.contraints.facet.Three;
import cn.touna.risk.api.enums.SystemErrorCodeEnum;
import cn.touna.risk.api.utils.JSONUtil;
import cn.touna.jss.common.entity.IdCardNameEntity;
import cn.touna.jss.common.factory.ResponseFactory;
import cn.touna.jss.common.factory.RestTemplateConfig;
import cn.touna.jss.common.filter.entity.WrappedHttpServletRequest;
import cn.touna.jss.common.properties.disconf.TianXingProperties;
import cn.touna.jss.common.util.HttpClientUtils;
import cn.touna.jss.common.util.JssConstant;
import cn.touna.jss.common.util.ValidUtil;
import cn.touna.jss.modules.adapter.ApiMapping;
import cn.touna.jss.modules.adapter.GatewayController;
import cn.touna.jss.modules.custom.carloan.entity.TrafficViolationEntity;
import cn.touna.jss.modules.third.tx.entity.TianXingRequestEntity;
import cn.touna.jss.modules.third.tx.entity.UnionPayRequest;
import cn.touna.jss.modules.third.tx.enums.TianXingEnum;
import cn.touna.risk.api.domain.Response;
import cn.touna.risk.api.exception.BusinessException;
import cn.touna.risk.api.exception.ServiceException;
import cn.touna.risk.api.http.HttpUtil;
import cn.touna.risk.api.http.ResultData;
import cn.touna.risk.cache.redis.RedisCache;
import cn.touna.risk.threadpool.common.util.ThreadPoolUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 天行数科调用
 *
 * @author wuwc
 */
@Service
public class TianXingService {
    private static final Logger LOGGER = LogManager.getLogger(TianXingService.class);

    @Autowired
    private TianXingProperties txProperties;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    GatewayController gatewayController;

    public static RestTemplate restTemplate = new RestTemplateConfig().httpsRestTemplate();


    /**
     * 天行企业信息查询接口请求
     *
     * @param request
     * @return
     * @throws Exception
     */
    @ApiMapping(value = "TianXing.getCompanyInfoData",desc = "天行.企业信息查询")
    public Response getCompanyInfoData(TianXingRequestEntity requestEntity) {
        Response response = new Response();
        try {
            Map<String, String> params = new HashMap<>();
            params.put("account", txProperties.getAccount());
            params.put("accessToken", getToken());
            params.put("key", requestEntity.getKey());
            params.put("keyType", requestEntity.getKeyType());
            params.put("mockType","EXIST");
            LOGGER.info("REQ 【天行企业信息查询接口请求】,params：{}", JSON.toJSONString(params));
            return handleTxRequest(txProperties.getCompanyInfoDataUrl(), params, true);
        } catch (Exception e) {
            LOGGER.error("调用【天行企业信息查询接口请求】异常,errMsg:{}", e);
            return response.fail(SystemErrorCodeEnum.JSS_CALL_EXTSYSTEM_ERROR, e.getMessage());
        }
    }


    /**
     * 天行企业模糊查询接口请求
     *
     * @param request
     * @return
     * @throws Exception
     */
    @ApiMapping(value = "TianXing.fuzzyQueryCompanyIn",desc = "天行.企业模糊查询")
    public Response fuzzyQueryCompanyIn(TianXingRequestEntity requestEntity) {
        Response response = new Response();
        try {
            StringBuffer sb = new StringBuffer();
            sb.append(txProperties.getFuzzyQuerycompanyUrl()+"?");
            sb.append("account=").append(txProperties.getAccount());
            sb.append("&accessToken=").append(getToken());
            sb.append("&key=").append(requestEntity.getKey());
            sb.append("&mockType=").append("EXIST");
            if(requestEntity.getPageIndex()>0){
                sb.append("&pageIndex=").append(requestEntity.getPageIndex());
            }
            JSONObject result = HttpClientUtils.httpGet(sb.toString());
            LOGGER.info("REQ 【天行企业模糊查询接口请求】,params：{}", sb.toString());
            boolean success = result.getBoolean("success");
            if (success) {
                return ResponseFactory.success(result.getJSONObject("data"));
            } else {
                String msg = result.getString("errorDesc");
                return ResponseFactory.fail(SystemErrorCodeEnum.JSS_EXTSYSTEM_RESP_FAIL, msg);
            }
        } catch (Exception e) {
            LOGGER.error("调用【天行企业模糊查询接口请求】异常,errMsg:{}", e);
            return response.fail(SystemErrorCodeEnum.JSS_CALL_EXTSYSTEM_ERROR, e.getMessage());
        }
    }



    /**
     * 天行个人工商信息查询接口
     *
     * @param requestEntity
     * @return
     */
    @ApiMapping(value = "TianXing.getMemberData",desc = "天行.个人工商信息查询")
    public Response getMemberData(TianXingRequestEntity requestEntity) {
        Response response = new Response();
        ValidUtil.checkRequestParams(requestEntity, Three.class);
        try {
            Map<String, String> params = new HashMap<>();
            params.put("account", txProperties.getAccount());
            params.put("accessToken", getToken());
            params.put("key", requestEntity.getIdCard());
//            params.put("mockType","EXIST");
            LOGGER.info("REQ 【天行个人工商信息查询接口请求】,params：{}", JSON.toJSONString(params));
            response =handleTxRequest(txProperties.getMemberInfoDataUrl(), params, true);
            if(response.getCode().equals("200")){

                JSONObject request =   getRequestParams();

                ThreadPoolUtil.submit("tianxingCompany", this, "loadCompanyData",request, response);
            }
            return response;
        } catch (Exception e) {
            LOGGER.error("RER【天行个人工商信息查询接口请求】异常,errMsg:{}", e);
            return response.fail(SystemErrorCodeEnum.JSS_CALL_EXTSYSTEM_ERROR, e.getMessage());
        }
    }

    private JSONObject getRequestParams() {
        JSONObject requestParams = null;
        try {
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            // 本次request请求的参数
            if(attributes == null || attributes.getRequest() == null)
                return null;
            if(attributes.getRequest() instanceof WrappedHttpServletRequest){
                requestParams = ((WrappedHttpServletRequest) attributes.getRequest()).getRequestParams();
                HttpServletRequest request = attributes.getRequest();
                requestParams.put("sysName",request.getHeader("sysName"));
                requestParams.put("productType",request.getHeader("productType"));
                requestParams.put("phaseName",request.getHeader("phaseName"));
                requestParams.put("applyNoType",request.getHeader("applyNoType"));
                requestParams.put("applyNo",request.getHeader("applyNo"));
                return requestParams;
            }
        } catch (IOException e) {
            LOGGER.error("获取请求参数失败，msg:{}", e.getMessage());
        }catch (Exception e){
            LOGGER.error(e.getMessage(),e);
        }
        return null;
    }


    private void loadCompanyData(JSONObject request,Response response ){
        JSONObject jsonObject = (JSONObject)response.getData();
        JSONArray jsonArray =  jsonObject.getJSONArray("corporates");
        loadCompanyInfo(request,jsonArray);
        JSONArray corporateShares =  jsonObject.getJSONArray("corporateShareholders");
        loadCompanyInfo(request,corporateShares);
    }

    private void loadCompanyInfo(JSONObject request,JSONArray jsonArray){
        if(jsonArray==null || jsonArray.size()<1){
            return ;
        }
        for (int i = 0; i <jsonArray.size() ; i++) {
            JSONObject company =(JSONObject)jsonArray.get(i);
            String regNo = company.getString("regNo");
            String entName = company.getString("entName");
            if(!StringUtils.isEmpty(regNo)){
                request.put("method", "TianXing.getCompanyInfoData");
                JSONObject param = new JSONObject();
                param.put("key",regNo);
                param.put("keyType","2");
                request.put("params", param);
                restTemplate.postForObject(txProperties.getReqUrl(), request, Response.class);
            }
            if(!StringUtils.isEmpty(entName)){
                request.put("method", "TianXing.getCompanyInfoData");
                JSONObject param = new JSONObject();
                param.put("key",entName);
                param.put("keyType","NAME");
                request.put("params", param);

                restTemplate.postForObject(txProperties.getReqUrl(), request, Response.class);
            }

        }
    }





    /**
     * 天行身份证验证查询接口请求
     *
     * @param request
     * @return
     * @throws Exception
     */
    @ApiMapping(value = "TianXing.getIdCardVerifyData",desc = "天行.实名认证")
    public Response getIdCardVerifyData(TianXingRequestEntity requestEntity) {
        Response response = new Response();
        ValidUtil.checkRequestParams(requestEntity, Second.class);
        try {
            Map<String, String> params = new HashMap<>();
            params.put("account", txProperties.getAccount());
            params.put("accessToken", getToken());
            params.put("name", requestEntity.getName());
            params.put("idCard", requestEntity.getIdCard());
            params.put("mockType","SAME");
            LOGGER.info("REQ 【天行身份证验证查询接口请求】,params：{}", JSON.toJSONString(params));
            return handleTxRequest(txProperties.getIdCardDataUrl(), params, true);
        } catch (Exception e) {
            LOGGER.error("调用【天行身份证验证查询接口请求】异常,errMsg:{}", e);
            return response.fail(SystemErrorCodeEnum.JSS_CALL_EXTSYSTEM_ERROR, e.getMessage());
        }
    }

    /**
     * 天行身份证照片查询接口请求
     *
     * @param request
     * @return
     * @throws Exception
     */
    @ApiMapping(value = "TianXing.getIdCardPhotoVerifyData",desc = "天行.证件照片验证")
    public Response getIdCardPhotoVerifyData(TianXingRequestEntity requestEntity) {
        Response response = new Response();
        ValidUtil.checkRequestParams(requestEntity, Four.class);
        try {
            Map<String, String> params = new HashMap<>();
            params.put("account", txProperties.getAccount());
            params.put("accessToken", getToken());
            params.put("name", requestEntity.getName());
            params.put("idCard", requestEntity.getIdCard());
            params.put("mockType","SAME");
            LOGGER.info("REQ 【天行身份证照片查询接口请求】,params：{}", JSON.toJSONString(params));
            return handleTxRequest(txProperties.getIdCardPhotoDataUrl(), params, true);
        } catch (Exception e) {
            LOGGER.error("RER【天行身份证照片查询】异常,errMsg:{}", e);
            return response.fail(SystemErrorCodeEnum.JSS_CALL_EXTSYSTEM_ERROR, e.getMessage());
        }
    }

    /**
     * 天行不良信息核查查询接口请求
     *
     * @param request
     * @return
     * @throws Exception
     */
    @ApiMapping(value = "TianXing.getNegativeInfoData",desc = "天行.不良信息核查查询")
    public Response getNegativeInfoData(TianXingRequestEntity requestEntity) {
        Response response = new Response();
        ValidUtil.checkRequestParams(requestEntity, Four.class);
        try {
            Map<String, String> params = new HashMap<>();
            params.put("account", txProperties.getAccount());
            params.put("accessToken", getToken());
            params.put("name", requestEntity.getName());
            params.put("idCard", requestEntity.getIdCard());
            params.put("escape", txProperties.getFlag());
            params.put("crime", txProperties.getFlag());
            params.put("drug", txProperties.getFlag());
            params.put("drugRelated", txProperties.getFlag());
            params.put("mockType","EXIST");
            LOGGER.info("REQ 【天行不良信息核查查询接口请求】,params：{}", JSON.toJSON(params));
            response = handleTxRequest(txProperties.getNegativeInfoDataUrl(), params, false);
            if(response.getCode().equals("200")){
                String data =(String) response.getData();
                JSONObject dataJson =  JSONObject.parseObject(data);
                response.setData(dataJson);
            }
            return response;
        } catch (Exception e) {
            LOGGER.error("调用【天行不良信息核查查询异常】,errMsg:{}", e);
            return response.fail(SystemErrorCodeEnum.JSS_CALL_EXTSYSTEM_ERROR, e.getMessage());
        }
    }

    /**
     * 银联三要素
     *
     * @param request
     * @return
     */
    @ApiMapping(value = "TianXing.threeElementValidate",desc = "天行.银联三要素查询")
    public Response threeElementValidate(UnionPayRequest.ThreeElementRequest requestEntity) {
        try {
            Map<String, String> params = new HashMap<>();
            params.put("account", txProperties.getAccount());
            params.put("accessToken", getToken());
            params.put("accountNO", requestEntity.getBankCardNo());
            params.put("name", requestEntity.getName());
            params.put("idCard", requestEntity.getIdCard());
            params.put("mockType","SAME");
            LOGGER.info("REQ 【天行银联三要素接口请求】,params：{}", JSON.toJSONString(params));
            return handleTxElementRequest(txProperties.getElement3Url(), params);
        } catch (Exception e) {
            LOGGER.error("RER【天行银联三要素接口】异常,errMsg:{}", e);
            return ResponseFactory.fail(SystemErrorCodeEnum.JSS_EXTSYSTEM_RESP_FAIL, e.getMessage());
        }
    }

    /**
     * 银联四要素
     *
     * @param request
     * @return
     */
    @ApiMapping(value = "TianXing.fourElementValidate",desc = "天行.银联四要素查询")
    public Response fourElementValidate(UnionPayRequest.FourElementRequest requestEntity) {
        try {
            Map<String, String> params = new HashMap<>();
            params.put("account", txProperties.getAccount());
            params.put("accessToken", getToken());
            params.put("accountNO", requestEntity.getBankCardNo());
            params.put("bankPreMobile", requestEntity.getMobile());
            params.put("name", requestEntity.getName());
            params.put("idCard", requestEntity.getIdCard());
            params.put("mockType","SAME");
            LOGGER.info("REQ 【天行银联四要素接口请求】,params：{}", JSON.toJSONString(params));
            return handleTxElementRequest(txProperties.getElement4Url(), params);
        } catch (Exception e) {
            LOGGER.error("RER【天行银联四要素接口异常】,errMsg:{}", e);
            return ResponseFactory.fail(SystemErrorCodeEnum.JSS_EXTSYSTEM_RESP_ERROR, e.getMessage());
        }
    }

    /**
     * 天行车辆违章接口
     * @param trafficEntity
     * @return
     */
    @ApiMapping(value = "TianXing.offences",desc = "天行.车辆违章接口")
    public Response trafficOffences(TrafficViolationEntity trafficEntity) {
        Response response = new Response();
        ValidUtil.checkRequestParams(trafficEntity);
        try {
            Map<String, String> params = new HashMap<>();
            params.put("account", txProperties.getAccount());
            params.put("accessToken", getToken());
            params.put("carNumber", trafficEntity.getCarNumber());
            params.put("carCode", trafficEntity.getCarCode());
            params.put("carDriveNumber", trafficEntity.getCarDriverNumber());
            params.put("mockType","EXIST");
            LOGGER.info("REQ 【天行车辆违章接口请求】,params：{}", JSON.toJSON(params));
            return handleTxRequest(txProperties.getOffencesUrl(), params, true);
        } catch (Exception e) {
            LOGGER.error("调用【天行车辆违章接口查询异常】,errMsg:{}", e);
            return response.fail(SystemErrorCodeEnum.JSS_CALL_EXTSYSTEM_ERROR, e.getMessage());
        }
    }

    /**
     * 天行收入
     *
     * @param request
     * @return
     */
//    @ApiMapping("TianXing.income")
    public Response income(IdCardNameEntity request) {
        try {
            Map<String, String> params = new HashMap<>();
            params.put("account", txProperties.getAccount());
            params.put("accessToken", getToken());
            params.put("name", request.getName());
            params.put("idCard", request.getIdCard());
            params.put("mockType","EXIST");
            return handleTxRequest(txProperties.getIncomeUrl(), params, false);
        } catch (Exception e) {
            return ResponseFactory.fail(SystemErrorCodeEnum.JSS_CALL_EXTSYSTEM_ERROR, e.getMessage());
        }
    }


    /**
     * 获取安全凭证码
     *
     * @return
     */
    private String getToken() throws Exception {
        // 在有效期内从缓存获取Token
        String cahceToken = redisCache.get(JssConstant.TOKEN_TIANXING_KEY);
        LOGGER.info("缓存的天行Token:{}", cahceToken);
        if (StringUtils.isNotBlank(cahceToken)) {
            return cahceToken;
        }
        String token = resetToken();
        if (StringUtils.isBlank(token)) {
            throw new ServiceException("登录天行服务失败");
        }
        return token;
    }

    /**
     * 过期重置token
     *
     * @return
     */
    private String resetToken() throws Exception {
        Map<String, String> params = new HashMap<>();
        params.put("account", txProperties.getAccount());
        params.put("signature", txProperties.getSignature());
        LOGGER.info("token请求参数为：{}", params);
        String tokenRes = HttpUtil.getInstance().post(txProperties.getAuthUrl(), params);
        LOGGER.info("token返回结果为: {}", tokenRes);
        if (StringUtils.isBlank(tokenRes)) {
            throw new BusinessException(TianXingEnum.TX_TOKEN_ERR);
        }
        boolean success = JSONUtil.getBoolean(tokenRes, "success", false);
        if (success) {
            String data = JSONUtil.getString(tokenRes, "data", null);
            if (StringUtils.isBlank(data)) {
                throw new BusinessException(TianXingEnum.TX_TOKEN_ERR);
            }
            String accessToken = JSONUtil.getString(data, "accessToken", null);
            //在有效期内缓存Token
            redisCache.set(JssConstant.TOKEN_TIANXING_KEY, accessToken, 20, TimeUnit.HOURS);
            return accessToken;
        }
        return null;
    }

    /**
     * 处理天行返回结果
     *
     * @param result
     * @return
     */
    private Response handleTxElementRequest(String url, Map<String, String> params) throws Exception {
        ResultData resultData = HttpUtil.getInstance().getData(url, params);
        if (401 == resultData.getStatus()) {
            //token过期，重置token
            String resetToken = resetToken();
            params.put("accessToken", resetToken);
            resultData = HttpUtil.getInstance().getData(url, params);
        }
        LOGGER.info("REQ 【天行返回结果】,result：{}", resultData);
        if (StringUtils.isBlank(resultData.getData())) {
            return ResponseFactory.fail(SystemErrorCodeEnum.JSS_EXTSYSTEM_RESP_ERROR);
        }
        boolean success = JSONUtil.getBoolean(resultData.getData(), "success", false);
        if (success) {
            JSONObject data = JSONUtil.getJSONObject(resultData.getData()).getJSONObject("data");
            String msg = data.getString("result");
            String flag = data.getString("checkStatus");
            if ("SAME".equals(flag)) {
                return ResponseFactory.success(resultData.getData());
            }
            return ResponseFactory.fail(SystemErrorCodeEnum.JSS_EXTSYSTEM_RESP_FAIL.getErrorCode(), msg);
        } else {
            return ResponseFactory.fail(SystemErrorCodeEnum.JSS_EXTSYSTEM_RESP_FAIL, JSONUtil.getString(resultData.getData(), "errorDesc", ""));
        }
    }

    /**
     * 处理天行返回结果
     *
     * @param result
     * @return
     */
    private Response handleTxRequest(String url, Map<String, String> params, boolean isDeal) throws Exception {
        ResultData resultData = HttpUtil.getInstance().getData(url, params);
        if (401 == resultData.getStatus()) {
            //token过期，重置token
            String resetToken = resetToken();
            params.put("accessToken", resetToken);
            resultData = HttpUtil.getInstance().getData(url, params);
        }
        LOGGER.info("REQ 【天行返回结果】,result：{}", resultData);
        if (StringUtils.isBlank(resultData.getData())) {
            return ResponseFactory.fail(SystemErrorCodeEnum.JSS_EXTSYSTEM_RESP_ERROR);
        }
        boolean success = JSONUtil.getBoolean(resultData.getData(), "success", false);
        if (success) {
            if (isDeal) {
                return ResponseFactory.success(JSONUtil.get(resultData.getData(), "data", null));
            }
            return ResponseFactory.success(resultData.getData());
        } else {
            return ResponseFactory.fail(SystemErrorCodeEnum.JSS_EXTSYSTEM_RESP_FAIL, JSONUtil.getString(resultData.getData(), "errorDesc", ""));
        }
    }

}
